package com.sunchangming.uniqname;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.nio.file.Paths;
import java.util.concurrent.CountDownLatch;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class ServerMain {
	private final static Logger logger = Logger.getLogger(ServerMain.class);
	private static CountDownLatch stop = new CountDownLatch(1);

	static com.google.protobuf.BlockingService service;

	static com.google.protobuf.BlockingService getBlockingService() {
		return service;
	}

	static public void stop() {
		stop.countDown();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		BasicConfigurator.configure();

		Options options = new Options();
		options.addOption("p", true, "port");
		options.addOption("h", false, "help");

		HelpFormatter formatter = new HelpFormatter();

		CommandLineParser parser = new PosixParser();
		final CommandLine cmd;
		try {
			cmd = parser.parse(options, args);
		} catch (ParseException ex) {
			formatter.printHelp("com.sunchangming.uniqname.ServerMain", options);
			return;
		}

		if (cmd.hasOption("h")) {
			formatter.printHelp("com.sunchangming.uniqname.ServerMain", options);
			return;
		}

		int port = 10000;
		if (cmd.hasOption('p')) {
			port = Integer.valueOf(cmd.getOptionValue('p'));
		}

		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
		} catch (Exception ex) {
			logger.info("载入MySQL失败", ex);
			return;
		}

		ServiceConfig.init(Paths.get("config.xml"));
		ServiceImpl si = new ServiceImpl();
		try {
			si.testJdbcConnection();
		} catch (Exception ex) {
			logger.error("测试数据库连接失败", ex);
			return;
		}
		service = UniqMsg.UniqNameService.newReflectiveBlockingService(si);

		NioSocketAcceptor acceptor = new NioSocketAcceptor();
		acceptor.getFilterChain().addLast("logger", new LoggingFilter());
		acceptor.getFilterChain().addLast("codec",
				new ProtocolCodecFilter(new com.sunchangming.uniqname.ProtobufCodecFactory(service, true)));

		acceptor.setHandler(new ServerIoHandler());
		try {
			acceptor.bind(new InetSocketAddress(port));
		} catch (IOException ex) {
			logger.error("绑定到端口" + port + "失败", ex);
			acceptor.dispose();
			return;
		}

		MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();

		ObjectName acceptorName;
		try {
			acceptorName = new ObjectName("com.sunchangming" + ":type=uniqname,name=ServerMXBean");

			mBeanServer.registerMBean(new Server(acceptor), acceptorName);
			mBeanServer.registerMBean(ServiceConfig.getInstance(), new ObjectName("com.sunchangming"
					+ ":type=uniqname,name=ServiceConfig"));

		} catch (Exception e) {
			logger.info("err", e);
		}

		try {
			stop.await();
		} catch (InterruptedException ex) {

		}
		acceptor.setCloseOnDeactivation(false);
		acceptor.unbind();
		for (IoSession ioSession : acceptor.getManagedSessions().values()) {
			if (ioSession.isConnected())
				ioSession.close(true);
		}
		acceptor.dispose();
		acceptor = null;
		logger.info("服务器关闭完毕");
	}
}
